package jstudy.gu.kit.tree;

import java.io.Serializable;
import java.util.*;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import jstudy.gu.kit.reflect.ReflectKit;
import lombok.AllArgsConstructor;

// 通用的树形结构搜索., 单一类型 // dep - user
@AllArgsConstructor
public class TreeSearch2<T> {
	private BaseMapper<T> mapper; //// 从数据库select 一条数据 selectById
	private String childrenField;// 子节点的名称给我,要求这是List<T>
	private String idField;// id字段名
	private String parentIdField;// parentId字段名
	private Object parentRootValue;// 根节点的parentId的值,也就默认的0

	private static boolean equals(Object o1, Object o2) {
		return o1 == o2 || (o1 != null && o1.equals(o2));
	}

	public List<T> search(List<T> flatNodes) {// 你要处理的节点的平面形式,也就是搜索的基本条目
		if (flatNodes == null || flatNodes.isEmpty()) {
			return flatNodes;
		}
		final List<T> roots = new LinkedList<>(); // 记载所有的根节点

		final Map<Serializable, T> nodes = new HashMap<>(); // 记录所有的节点,包括跟,缓存避免重复
//		flatNodes.forEach(t -> nodes.put(ReflectKit.getField(t, idField), t));// 先把所有基本节点缓存起来
		for (T t : flatNodes) {
			nodes.put(ReflectKit.getFieldValue(t, idField), t);
		}

		boolean processed = false; // 是否处理过
		List<T> plist = flatNodes; // 要循环的节点,这是一个tmp节点,当前正在处理的节点列表
		Set<Serializable> rids = new HashSet<>();
		Serializable tid;
		while (!processed || !plist.isEmpty()) {
			processed = true;
			flatNodes = plist;
			plist = new LinkedList<>();
			for (T t : flatNodes) {
				if (equals(ReflectKit.getFieldValue(t, parentIdField), parentRootValue)
						&& !rids.contains((tid = ReflectKit.getFieldValue(t, idField)))) {
					roots.add(t);
					rids.add(tid);
				} else {
					Serializable parentId = ReflectKit.getFieldValue(t, parentIdField);
					T parent = nodes.get(parentId);
					if (parent == null) {
						parent = mapper.selectById(parentId);
						nodes.put(parentId, parent);
					}
					// nodes 判断parentid 是否存在,如果存在,则直接返回,如果不存在,执行selectByID,.并且把结果存到nodes中
					if (parent != null) {
						List<T> pChildren = ReflectKit.getFieldValue(parent, childrenField);
						if (pChildren == null) {
							pChildren = new ArrayList<>();
							ReflectKit.setFieldValue(parent, childrenField, pChildren);
						}
						pChildren.add(t);
						if (!plist.contains(parent)) {
							plist.add(parent);
						}
					}

				}
			}
		}
		return roots;

	}

}